/*
 * License GNU LGPL
 * Copyright (C) 2012 Amrullah <amrullah@panemu.com>.
 */
package com.abc.cheque.ui.table;


import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Control;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

import com.abc.cheque.common.TiwulFXUtil;
import com.abc.cheque.common.TableCriteria.Operator;
import com.abc.cheque.control.NumberField;

/**
 *
 * @author amrullah
 */
public class NumberColumn<S extends Object, T extends Number> extends BaseColumn<S, T> {

    private boolean grouping = true;
    private int maxLength = 10;
    private Class<T> clazz;
    private NumberField<T> searchInputControl = new NumberField<>(null);
    protected String pattern = "###,###";
    protected DecimalFormat formatter = TiwulFXUtil.getDecimalFormat();
    private SearchMenuItemBase<T> searchMenuItem = new SearchMenuItemBase<T>(this) {
        @Override
        protected Node getInputControl() {
            return searchInputControl;
        }

        @Override
        protected List<Operator> getOperators() {
            List<Operator> lst = new ArrayList<>();
            lst.add(Operator.eq);
            lst.add(Operator.ne);
            lst.add(Operator.lt);
            lst.add(Operator.le);
            lst.add(Operator.gt);
            lst.add(Operator.ge);
            lst.add(Operator.is_null);
            lst.add(Operator.is_not_null);
            return lst;
        }

        @Override
        protected T getValue() {
            return searchInputControl.getValue();
        }
    };

    public NumberColumn(String propertyName, Class<T> clazz) {
        this(propertyName, clazz, 100);
    }

    public NumberColumn(String propertyName, Class<T> clazz, double prefWidth) {
        super(propertyName, prefWidth);
        setAlignment(Pos.CENTER_RIGHT);
        this.clazz = clazz;
        Callback<TableColumn<S, T>, TableCell<S, T>> cellFactory =
                new Callback<TableColumn<S, T>, TableCell<S, T>>() {
                    @Override
                    public TableCell call(TableColumn p) {
                        return new NumberTableCell();
                    }
                };
        setCellFactory(cellFactory);
        formatter.setParseBigDecimal(clazz.equals(BigDecimal.class));
        formatter.applyPattern(getPattern(grouping));
        searchInputControl.setNumberType(clazz);
    }

    public boolean isGrouping() {
        return grouping;
    }

    @Override
    MenuItem getSearchMenuItem() {
        if (getDefaultSearchValue() != null) {
            searchInputControl.setValue(getDefaultSearchValue());
        }
        return searchMenuItem;
    }

    public void setGrouping(boolean grouping) {
        this.grouping = grouping;
        pattern = getPattern(grouping);
        formatter.applyPattern(pattern);
    }

    @Override
    public String convertToString(T value) {
        return value== null ? "" : formatter.format(value);
    }

    @Override
    protected T convertFromString_Impl(String stringValue) {
        return searchInputControl.castToExpectedType(stringValue);
    }
    
    /**
     * Set maximum character length is acceptable in input field
     *
     * @param maxLength
     */
    public void setMaxLength(int maxLength) {
        this.maxLength = maxLength;
    }

    public int getMaxLength() {
        return maxLength;
    }

    protected String getPattern(boolean grouping) {
        if (clazz.equals(Integer.class) || clazz.equals(Long.class)) {
            if (grouping) {
                formatter.setParseBigDecimal(clazz.equals(BigDecimal.class));
                return "###,###";
            } else {
                return "###";
            }
        } else {
            if (grouping) {
                formatter.setParseBigDecimal(clazz.equals(BigDecimal.class));
                return "###,##0.00";
            } else {
                return "##0.00";
            }
        }
    }

    public class NumberTableCell extends BaseCell<S, T> {

        private NumberField<T> textField;

        public NumberTableCell() {
            super();
            this.setAlignment(NumberColumn.this.getAlignment());
        }

        @Override
        protected void setValueToEditor(T value) {
            textField.setValue(value);
        }

        @Override
        protected T getValueFromEditor() {
            return textField.getValue();
        }

        @Override
        protected Control getEditor() {
            if (textField == null) {
                textField = new NumberField<>(clazz);
                textField.setMaxLength(maxLength);
            }
            return textField;
        }
        @Override
        protected String getString(T value) {
            return value== null ? "" : formatter.format(value);
        }

        @Override
        public void cancelEdit() {
            super.cancelEdit();
        }
        
    }
    
}
